home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Megarom
/
Megarom Macintosh CD Software (Quantum Leap)(1992).iso
/
APPS
/
Re-Animator ƒ
/
Re-animator.c
< prev
Wrap
C/C++ Source or Header
|
1992-02-12
|
19KB
|
722 lines
/*
Re-Animator 1.1.0: Generic animation player.
Written by: Russell LaValle
Correspondence: 12-i Bimini Crossing
Hampton, VA 23666
Re-Animator is a relatively simple ( in retrospect ) PICS animation
player. It will read any file with PICTs resources and animate them
very quickly using CopyBits.
Enhancements since Re-Animator 1.0.1:
1. The user now has the option to make the animation window appear
on the left edge of the screen- greatly improving speed.
2. As well as displaying each frame as it's loaded in, Re-Animator
shows a small window with a growing bar signifying its progress
loading the file.
3. The user can have the Open dialog box display all files or just
PICS files.
4. The speed of the animation can be selected from the menu bar.
5. Added a less boring Finder Icon, and the version resource to
the resource file.
One problem I found with other animation solutions using
only DrawPicture, was that they were extremely slow. Another problem
was when they animated certain PICTs, they didn't overwrite the
underlying PICT on the screen with a new one- they just peformed an OR
operation. Clearing the last PICT manually, slowed the animation even
more. I couldn't find a share/freeware program to do this, so I wrote
my own.
This is my first "real" Macintosh program. I'll continue
to improve it as I find/hear improvements needed.
Re-Animator is Freeware. Do anything you'd like with it.
I'd like to thank Dave Mark & CartWright Reed for the excellent
Macintosh Programming Primer Volume I. Also extremely helpful were
Brigham Stevens' offScreenBitMap.c routines. And of course, Think C is
an awesome/inexpensive developement environment.
If you have a very large animation to run, you may need to enlarge
the application memory size in the Get Info box.
Feel free to write me at the above address to comment or make
suggestions. I can also be reached on America Online: Russell FP
*************************************
* I did not include the Proj file *
* because it was huge with the *
* inclusion of the ANSI library. *
* When you create the project, just *
* be sure to add: *
* 1. Re-Animator.c *
* 2. MacTraps *
* 3. ANSI *
*************************************
*/
#include <stdlib.h>
#define NIL_POINTER 0L
#define NIL_STRING "\p"
#define A_SECOND 60
#define NOTHING NIL_STRING
#define NO_FILTER NIL_POINTER
#define NO_HOOK NIL_POINTER
#define ALL_TYPES -1
#define MIN_SLEEP 0L
#define NIL_MOUSE_REGION 0L
#define REMOVE_ALL_EVENTS 0
#define RECT_LEFT 10
#define RECT_TOP 10
#define RECT_RIGHT 212
#define RECT_BOTTOM 25
#define PEN_HEIGHT 13
#define CANT_OPEN_FILE 400
#define CANT_GET_RES 401
#define OUT_OF_MEMORY 402
#define NO_WINDOW_RES 403
#define NO_PICTS 404
#define APPLE_MENU_ID 400
#define FILE_MENU_ID 401
#define SPEED_MENU_ID 403
#define OPTION_MENU_ID 404
#define OUR_MBAR 400
#define PROG_WINDOW 400
#define ABOUT_ITEM 1
#define OPEN_ITEM 1
#define CLOSE_ITEM 2
#define RUN_ITEM 4
#define QUIT_ITEM 6
#define FAST_AS_POS 1
#define ONE_SIXTIETH 2
#define ONE_THIRTIETH 3
#define ONE_TWENTIETH 4
#define ONE_FIFTEENTH 5
#define ONE_TENTH 6
#define ONE_FIFTH 7
#define SUPER_FAST 1
#define PICS_ONLY 3
#define ADD_CHECK TRUE
#define REMOVE_CHECK FALSE
#define YES_GO_AWAY TRUE
#define MOVE_TO_FRONT -1L
#define LEAVE_THERE FALSE
#define VISIBLE TRUE
#define ABOUT_ALERT 400
#define ERROR_ALERT_ID 401
#define MOTHER_ERROR "\pCan't tell what error happened... Sorry."
Rect destRect, sourceRect, picRect, frame1Rect, progressRect;
int numFrames, horizDiff, vertDiff, addFlag,
animSpeed, lastSpeed, windRectTop, windRectLeft;
Boolean notDone = TRUE,
fileLoaded, doneAnimating, errorDetected, superFastFlag,
PICSOnlyFlag;
BitMap *theAnimation, lastBitMap;
WindowRecord animWindRec;
WindowPtr animateWindow, progressWindow;
SFReply theReply;
MenuHandle theAppleMenu, theFileMenu, theSpeedMenu, theOptionMenu;
EventRecord theEvent;
PicHandle thePict;
/********************************** main *****************/
main()
{
ToolBoxInit(); /* call initialization routines */
MenuBarInit();
InitProgWindow();
Alert( ABOUT_ALERT, NIL_POINTER ); /* display initial about box */
MainLoop();
}
/********************************** ToolBoxInit **********/
ToolBoxInit()
{
InitGraf( &thePort ); /* standard initialization stuff */
InitFonts();
FlushEvents( everyEvent, 0 );
InitWindows();
InitMenus();
TEInit();
InitDialogs( NIL_POINTER );
InitCursor();
}
/********************************** MenuBarInit **********/
MenuBarInit()
{
Handle theMenuBar;
theMenuBar = GetNewMBar( OUR_MBAR ); /* load the menu bar */
SetMenuBar( theMenuBar ); /* make it active */
theAppleMenu = GetMHandle( APPLE_MENU_ID );
AddResMenu( theAppleMenu, 'DRVR' );
theFileMenu = GetMHandle( FILE_MENU_ID );
theSpeedMenu = GetMHandle( SPEED_MENU_ID );
theOptionMenu = GetMHandle( OPTION_MENU_ID );
lastSpeed = 1;
CheckItem( theSpeedMenu, lastSpeed, ADD_CHECK );
PICSOnlyFlag = TRUE;
CheckItem( theOptionMenu, PICS_ONLY, PICSOnlyFlag );
superFastFlag = FALSE;
DrawMenuBar(); /* and display it */
}
/********************************** MainLoop *************/
MainLoop()
{
do
{
errorDetected = FALSE; /* reset Error flag each time around */
HandleEvent();
} while ( notDone ); /* keep going until we're done */
CloseFile(theAnimation);
}
/********************************** HandleEvent **********/
HandleEvent()
{
char theKey;
WaitNextEvent( everyEvent, &theEvent, /* return an event */
MIN_SLEEP, NIL_MOUSE_REGION );
switch ( theEvent.what )
{
case mouseDown: /* check for mouse and */
HandleMouseDown(); /* keyboard events */
break;
case keyDown:
case autoKey:
theKey = theEvent.message & charCodeMask;
if (( theEvent.modifiers & cmdKey ) != 0 )
HandleMenuChoice( MenuKey( theKey ));
break;
case updateEvt:
if ( ( WindowPtr )theEvent.message == animateWindow )
{
BeginUpdate( theEvent.message );
DrawFrame( theAnimation );
EndUpdate( theEvent.message );
}
break;
} /* switch */
}
/********************************** HandleMouseDown ******/
HandleMouseDown()
{
WindowPtr theWindow;
short int thePart;
long int menuChoice;
thePart = FindWindow( theEvent.where, &theWindow );
switch ( thePart )
{
case inMenuBar:
menuChoice = MenuSelect( theEvent.where );
HandleMenuChoice( menuChoice );
break;
case inSysWindow:
SystemClick( &theEvent, theWindow );
break;
} /* case */
}
/********************************** HandleMenuChoice *****/
HandleMenuChoice( long int menuChoice )
{
int theMenu, theItem;
if ( menuChoice != 0 )
{
theMenu = HiWord( menuChoice ); /* Get which item of which */
theItem = LoWord( menuChoice ); /* menu was selected. */
switch ( theMenu )
{
case APPLE_MENU_ID:
HandleAppleChoice( theItem );
break;
case FILE_MENU_ID:
HandleFileChoice( theItem );
break;
case SPEED_MENU_ID:
HandleSpeedChoice( theItem );
break;
case OPTION_MENU_ID:
HandleOptionChoice( theItem );
break;
} /* case */
} /* if */
HiliteMenu( 0 );
}
/********************************** HandleAppleChoice ****/
HandleAppleChoice( int theItem )
{
Str255 accName;
int accNumber;
short int itemNumber;
switch ( theItem )
{
case ABOUT_ITEM:
Alert( ABOUT_ALERT, NIL_POINTER ); /* generic alert to */
break; /* show about info */
default:
GetItem( theAppleMenu, theItem, accName ); /* Get and run */
accNumber = OpenDeskAcc( accName ); /* a DA. */
break;
} /* switch */
}
/********************************** HandleFileChoice *****/
HandleFileChoice( int theItem )
{
switch ( theItem )
{
case OPEN_ITEM:
OpenFile();
break;
case CLOSE_ITEM:
CloseFile(theAnimation);
break;
case RUN_ITEM:
AnimateThem();
break;
case QUIT_ITEM:
notDone = FALSE;
break;
} /* switch */
}
/********************************** HandleSpeedChoice ****/
HandleSpeedChoice( int theItem )
{
switch ( theItem )
{
case FAST_AS_POS:
animSpeed = 0;
break;
case ONE_SIXTIETH:
animSpeed = 1;
break;
case ONE_THIRTIETH:
animSpeed = 2;
break;
case ONE_TWENTIETH:
animSpeed = 3;
break;
case ONE_FIFTEENTH:
animSpeed = 4;
break;
case ONE_TENTH:
animSpeed = 6;
break;
case ONE_FIFTH:
animSpeed = 12;
break;
} /* switch */
CheckItem( theSpeedMenu, lastSpeed, REMOVE_CHECK );
CheckItem( theSpeedMenu, theItem, ADD_CHECK );
lastSpeed = theItem;
}
/**********************************HandleOptionChoice ****/
HandleOptionChoice( int theItem )
{
switch ( theItem )
{
case SUPER_FAST:
superFastFlag = !superFastFlag;
if ( fileLoaded )
if ( superFastFlag )
MoveWindow( animateWindow, 0, windRectTop,
LEAVE_THERE );
else
MoveWindow( animateWindow, windRectLeft, windRectTop,
LEAVE_THERE );
CheckItem( theOptionMenu, SUPER_FAST, superFastFlag );
break;
case PICS_ONLY:
PICSOnlyFlag = !PICSOnlyFlag;
CheckItem( theOptionMenu, PICS_ONLY, PICSOnlyFlag );
break;
} /* switch */
}
/********************************** OpenFile *************/
OpenFile()
{
GetPicsFile();
if (theReply.good)
{
LoadPics();
if ( !( errorDetected ) ) /* If everything's */
{ /* fine, enable and */
EnableItem( theFileMenu, CLOSE_ITEM ); /* disable certain */
EnableItem( theFileMenu, RUN_ITEM ); /* menu items. */
DisableItem( theFileMenu, OPEN_ITEM );
} /* if */
} /* if */
}
/********************************** GetPicsFile **********/
GetPicsFile()
{
Point dialogLoc;
SFTypeList fileTypes;
int numTypes;
dialogLoc.h = 80; /* set up location to place select */
dialogLoc.v = 80; /* dialog, then set type of file to */
fileTypes[ 0 ] = 'PICS'; /* show */
if ( PICSOnlyFlag )
numTypes = 1;
else
numTypes = ALL_TYPES;
SFGetFile( dialogLoc, NOTHING, NO_FILTER, numTypes,
&fileTypes, NO_HOOK, &theReply); /* Call file select */
} /* dialog. */
/********************************** CloseFile ************/
CloseFile(BitMap *animation)
{
OSErr theResult;
int i;
if ( fileLoaded )
{
theResult = FSClose( theReply.vRefNum ); /* Close the file. */
for ( i=0; i < numFrames; i++, animation++ )
{
FreeBitMap( animation ); /* Release memory. */
} /* for */
free( theAnimation );
free( &lastBitMap );
CloseWindow( animateWindow );
fileLoaded = FALSE;
DisableItem( theFileMenu, RUN_ITEM ); /* Enable/disable */
DisableItem( theFileMenu, CLOSE_ITEM ); /* appropriate menu */
EnableItem( theFileMenu, OPEN_ITEM ); /* items. */
} /* if */
}
/********************************** LoadPics *************/
LoadPics()
{
short int resRefNum;
int i, incStep;
BitMap *animation;
GrafPort tempPort;
if (( resRefNum = OpenRFPerm( theReply.fName, /* Open the file. */
theReply.vRefNum, fsRdPerm )) == -1 )
{
ErrorHandler( CANT_OPEN_FILE );
}
else
{
numFrames = Count1Resources( 'PICT' ); /* find # of PICTs */
if ( numFrames > 0 )
{
if ( 200 % numFrames )
addFlag = 1;
else
addFlag = 0;
theAnimation = ( BitMap * ) calloc( (unsigned)(numFrames),
sizeof(BitMap) ); /* allocate array */
animation = theAnimation;
GetMyPict( 0, animation );
GetAnimWindow( frame1Rect );
InitProgress();
OpenPort( &tempPort );
NewBitMap( &frame1Rect, &lastBitMap );
LoadPicture( animation++, 0, &tempPort );
fileLoaded = TRUE; /* set flag */
if ( numFrames > 1 )
{
for ( i=1; i < numFrames; i++, animation++ )
{
GetMyPict( i, animation );
LoadPicture( animation, i, &tempPort ); /* fill fields */
} /* for */
} /* if */
ClosePort( &tempPort );
HideWindow( progressWindow );
DrawFrame( theAnimation );
SetPort( progressWindow );
PaintRect( &progressRect );
} /* if */
else
{
FSClose( theReply.vRefNum ); /* if no PICTs, close file */
ErrorHandler( NO_PICTS ); /* display error message */
} /* else */
} /* else */
}
/********************************** GetMyPict ***********/
GetMyPict( int frameNum, BitMap *theMap )
{
thePict = (PicHandle)Get1IndResource( 'PICT', frameNum + 1 );
if ( ResError() == resNotFound )
{
ErrorHandler( CANT_GET_RES );
} /* if */
else
{
picRect = ( **thePict ).picFrame;
RemoveSpace( &picRect, frameNum );
if ( frameNum == 0 )
{
frame1Rect = picRect;
}
NewBitMap( &frame1Rect, theMap ); /* allocate memory */
if ( MemErr )
{
DisposHandle( thePict ); /* if not enough memory */
ErrorHandler( OUT_OF_MEMORY ); /* display message and */
} /* if */
} /* else */
}
/********************************** LoadPicture **********/
LoadPicture( BitMap *theMap, int iteration, GrafPort *tPort )
{
int hDraw;
SetPort( tPort );
CopyBits( &lastBitMap, theMap, &frame1Rect, &frame1Rect,
srcCopy, NIL_POINTER );
SetPortBits( theMap ); /* draw the PICT in */
FillRect( &picRect, white ); /* each BitMap that */
DrawPicture( thePict, &picRect ); /* we allocated */
DisposHandle( thePict );
CopyBits( theMap, &lastBitMap, &frame1Rect, &frame1Rect,
srcCopy, NIL_POINTER );
SetPort( animateWindow );
DrawFrame( theMap );
SetPort( progressWindow );
hDraw = 200 * ( iteration + 1 ) / numFrames + RECT_LEFT + addFlag;
LineTo ( hDraw, RECT_TOP + 1 );
}
/********************************** InitProgWindow *******/
InitProgWindow()
{
progressWindow = GetNewWindow( PROG_WINDOW, NIL_POINTER,
MOVE_TO_FRONT );
PenMode( patCopy );
animSpeed = 0;
}
/********************************** InitProgress *********/
InitProgress()
{
SelectWindow( progressWindow );
SetPort( progressWindow );
SetRect ( &progressRect, RECT_LEFT, RECT_TOP,
RECT_RIGHT, RECT_BOTTOM );
ShowWindow( progressWindow );
FillRect( &progressRect, white );
PenSize( 1, 1 );
PenPat( black );
FrameRect ( &progressRect );
MoveTo( 60, 40 );
DrawString( "\pLoading PICTs...");
MoveTo( RECT_LEFT + 1, RECT_TOP + 1 );
PenSize( 1, PEN_HEIGHT );
PenPat( gray );
}
/********************************** FreeBitMap ***********/
FreeBitMap( BitMap *Bits )
{
DisposPtr( Bits->baseAddr ); /* free up a BitMap Ptr */
Bits->baseAddr = NIL_POINTER; /* and it's memory */
SetRect( &Bits->bounds, 0,0,0,0 );
Bits->rowBytes = 0;
}
/********************************** NewBitMap ************/
NewBitMap( Rect *frame, BitMap *theMap )
{
int size, rbytes;
CalcOffScreen( frame, &size, &rbytes ); /* find amount of mem. */
theMap->rowBytes = rbytes; /* to allocate, and set */
theMap->bounds = *frame; /* up a Ptr to do that */
theMap->baseAddr = NewPtr( size );
}
/********************************** CalcOffScreen ********/
CalcOffScreen( frame, needed, rows )
register Rect *frame;
register int *needed;
register int *rows;
{
*rows = (((( frame->right) - ( frame->left )) + 15)/16 ) * 2;
*needed = (( *rows ) * (( frame->bottom ) - ( frame->top )));
}
/********************************** GetAnimWindow ************/
GetAnimWindow( Rect theRect )
{
Rect windRect;
sourceRect = theRect;
destRect = theRect;
GetContent( &windRect );
ClipPicOrWindow( &windRect );
windRectTop = windRect.top;
windRectLeft = windRect.left;
if ( superFastFlag )
OffsetRect( &windRect, -( windRect.left ), 0 );
animateWindow = NewWindow( &animWindRec, &windRect, "\pRe-Animator",
VISIBLE, plainDBox, MOVE_TO_FRONT,
YES_GO_AWAY, 8 );
}
/********************************** GetContent ***********/
GetContent(Rect *windRect)
{
*windRect = screenBits.bounds; /* determine a baseline */
windRect->top += ( MBarHeight + 2 ); /* window size by coming in */
windRect->bottom -= 2; /* from top ( top + MBAR ) */
/* and bottom. */
}
/********************************** ClipPicOrWindow ******/
ClipPicOrWindow( Rect *windRect)
{
int windWidth, windHeight,
rectWidth, rectHeight;
windWidth = windRect->right - windRect->left;
windHeight = windRect->bottom - windRect->top;
rectWidth = sourceRect.right;
rectHeight = sourceRect.bottom;
if ( rectWidth > windWidth )
{
sourceRect.left = ( rectWidth - windWidth )/2; /* clip center */
sourceRect.right = sourceRect.left + windWidth; /* of picture */
destRect.right = windWidth; /* horizontally */
} /* if */
else
{
windRect->left += ( windWidth - rectWidth )/2; /* size window */
windRect->right = windRect->left + rectWidth; /* horizontally */
} /* else */
if ( rectHeight > windHeight )
{
sourceRect.top = ( rectHeight - windHeight )/2; /* clip center */
sourceRect.bottom = sourceRect.top + windHeight; /* of picture */
destRect.bottom = windHeight; /* vertically */
} /* if */
else
{
windRect->top += ( windHeight - rectHeight )/2; /* size window */
windRect->bottom = windRect->top + rectHeight; /* vertically */
} /* else */
}
/********************************** RemoveSpace **********/
RemoveSpace( Rect *theRect, int frameNum )
{
if ( frameNum == 0 )
{
horizDiff = theRect->left;
vertDiff = theRect->top;
}
OffsetRect( theRect, -horizDiff, -vertDiff );
}
/********************************** AnimateThem **********/
AnimateThem()
{
int i;
long int endTicks;
BitMap *animation;
if ( fileLoaded )
{
doneAnimating = FALSE;
SetPort( progressWindow );
HideCursor();
do
{
for ( i=0, animation = theAnimation; i < numFrames;
i++, animation++) /* run through PICS */
{
endTicks = TickCount() + animSpeed;
DrawFrame( animation );
if ( animSpeed > FAST_AS_POS )
while ( TickCount() < endTicks );
if ( Button() )
{
doneAnimating = TRUE;
break;
} /* if */
} /* for */
} while ( !( doneAnimating )); /* til mouse button pressed */
ShowCursor();
} /* if */
}
/********************************** DrawFrame ************/
DrawFrame( BitMap *theMap )
{
CopyBits( theMap, /* from BitMap */
&( animWindRec.port.portBits ), /* to BitMap */
&sourceRect, /* from Rect */
&destRect, /* to Rect */
srcCopy, /* xfer mode */
NIL_POINTER ); /* mask region */
}
/********************************** ErrorHandler *********/
ErrorHandler( int stringNum )
{
StringHandle errorStringH;
if (( errorStringH = GetString( stringNum )) == NIL_POINTER )
ParamText( MOTHER_ERROR, NIL_STRING, NIL_STRING,
NIL_STRING ); /* If we can't find error message, */
else /* show panic message. */
{
HLock( errorStringH ); /* find error message to display */
ParamText( *errorStringH, NIL_STRING, NIL_STRING, NIL_STRING );
HUnlock( errorStringH );
}
StopAlert( ERROR_ALERT_ID, NIL_POINTER ); /* show alert, and */
errorDetected = TRUE; /* set flag */
ExitToShell();
}